
package vv.lines.core.animations;

import vv.lines.core.Ball;
import vv.lines.core.BallController;
import vv.lines.core.Cell;
import vv.lines.core.Field;
import vv.lines.core.context.ContextHolder;
import vv.lines.view.ViewTimer;
import vv.lines.view.ViewTimerListener;

import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.PriorityBlockingQueue;

import static vv.lines.core.animations.AnimationType.ACTIVE;

/**
 *
 * @author vpotapenko
 */
public class AnimationHelper extends ContextHolder implements ViewTimerListener {

    private BlockingQueue<Animation> queue;
    private Field field;
    private BallController ballController;

    public AnimationHelper(BallController ballController, Field field) {
        super(field.getContext());

        this.ballController = ballController;
        this.field = field;
        ViewTimer viewTimer = getViewFactory().createViewTimer(this);
        viewTimer.start();

        queue = new PriorityBlockingQueue<Animation>(11, new AnimationComparator());
    }

    public void dispatchTimer() {
        if (queue.isEmpty()) return;

        Animation current = queue.peek();
        current.updateKey();
        repaintField();

        if (current.hasAnimation()) return;

        dispatchCancelAnimation(current);
    }

    public void stopActiveAnimation() {
        Animation animation = findActiveAnimation();
        if (animation != null) dispatchCancelAnimation(animation);
    }

    private void dispatchCancelAnimation(Animation animation) {
        queue.remove(animation);
        
        ballController.dispatchCancelAnimation(animation);
    }

    public void addActiveAnimation(Ball ball) {
        addAnimation(Collections.singleton(ball), ACTIVE, Integer.MAX_VALUE);
    }

    public void addMoveAnimation(Ball ball, List<Cell> path) {
        Animation animation = addAnimation(Collections.singleton(ball), AnimationType.MOVE,
                queue.size());
        animation.setCells(path);
    }

    public void addShowAnimation(Collection<Ball> balls) {
        addAnimation(balls, AnimationType.SHOW);
    }

    public void addHideAnimation(Collection<Ball> balls) {
        addAnimation(balls, AnimationType.HIDE);
    }

    private Animation addAnimation(Collection<Ball> target, AnimationType type) {
        return addAnimation(target, type, queue.size());
    }

    private Animation addAnimation(Collection<Ball> target, AnimationType type ,int priority) {
        Animation animation = getViewFactory().createAnimation(type);

        animation.setTarget(target);
        animation.setPriority(priority);

        queue.add(animation);

        return animation;
    }

    private Animation findActiveAnimation() {
        for (Animation animation : queue) {
            if (animation.getType() == ACTIVE) return animation;
        }
        return null;
    }

    private void repaintField() {
        if (field != null) field.getView().repaint();
    }
}
